Load Packages

library(tidyverse)
library(ggthemes)
library(scales)
library(readxl)
library(plotly)

Making Dataframes

color_a <- c("#58b5e1","#1c5b5a","#46ebdc","#1f4196","#e28de2","#818bd7","#e4ccf1","#82185f","#f849b6","#000000","#5e34bc","#b7d165","#30d52e","#ff5357")
color_na <- c("#1c5b5a","#46ebdc","#e28de2","#818bd7","#e4ccf1","#82185f","#f849b6","#000000","#5e34bc","#30d52e","#ff5357")
counties <- c('Anson', 'Cabarrus', 'Catawba', 'Chester', 'Cleveland', 'Gaston', 'Iredell', 'Lancaster', 'Lincoln', 'Mecklenburg', 'Rowan', 'Stanly', 'Union', 'York')
attainment_lvl <- c('Highest Degree: Less than a High School Diploma', 'Highest Degree: High School Diploma', 'Highest Degree: Some College, No Degree', "Highest Degree: Associate's Degree", "Highest Degree: Bachelor's Degree", "Highest Degree: Graduate or Professional Degree")
foreign_detail <- c('Foreign-Born: Africa', 'Foreign-Born: Asia', 'Foreign-Born: Europe', 'Foreign-Born: Latin America', 'Place of Birth Total')

countypop <- rbind(read_csv("cc-est2019-agesex-37.csv", show_col_types = F),
                   read_csv("cc-est2019-agesex-45.csv", show_col_types = F)) %>%
  select(-SUMLEV, -STATE, -COUNTY) %>%
  mutate(CTYNAME = gsub(' County', '', CTYNAME),
         YEAR = as.integer(YEAR + 2007)) %>%
  filter(CTYNAME %in% counties, YEAR >= 2010,
         !(STNAME == 'South Carolina' & CTYNAME == 'Union')) %>%
  distinct()
# Year 3 is 2010, Year 12 is 2019

# Making Charlotte Region
cr <- countypop[1:10,] %>%
  mutate(CTYNAME = 'Charlotte Region')
for(i in 4:length(colnames(countypop))) {
  for(j in 1:10){
    cr[j,i] <- sum((countypop %>% filter(YEAR == j+2009))[i])
  }
}

# Making Age & Gender data frame
pop_age_gender <- rbind(countypop, cr)
countypop <- cr %>% transmute(YEAR = YEAR, CHARLOTTEPOP = POPESTIMATE) %>% right_join(countypop, by = 'YEAR') %>% mutate(PROPORTION = POPESTIMATE / CHARLOTTEPOP) %>%
  group_by(CTYNAME) %>%
  mutate(CHANGE = round(ifelse(YEAR == 2010, 0, POPESTIMATE/lag(POPESTIMATE, default = first(YEAR)) - 1),4)) %>%
  ungroup()

pop_age_gender <- pop_age_gender %>%
  select(-contains('_TOT'), -POPEST_FEM, -POPEST_MALE, -AGE16PLUS_MALE, -AGE16PLUS_FEM, -AGE18PLUS_FEM, -AGE18PLUS_MALE, -UNDER5_FEM, -UNDER5_MALE, -AGE1544_FEM, -AGE1544_MALE, -MEDIAN_AGE_FEM, -MEDIAN_AGE_MALE, -AGE65PLUS_FEM,-AGE65PLUS_MALE, -AGE513_FEM, -AGE513_MALE, -AGE4564_FEM, -AGE4564_MALE, -AGE2544_FEM, -AGE2544_MALE, -AGE1824_FEM, -AGE1824_MALE, -AGE1417_FEM, -AGE1417_MALE) %>%
  rename(AGE004_FEM = AGE04_FEM, AGE004_MALE = AGE04_MALE, AGE0509_MALE = AGE59_MALE, AGE0509_FEM = AGE59_FEM)
pop_age_gender <- pop_age_gender %>%
  pivot_longer(cols = colnames(pop_age_gender[,5:40]), names_to = 'DEMO', values_to = 'POP') %>%
  mutate(PERCENTAGE = POP/POPESTIMATE)
pop_age_gender <- pop_age_gender %>%
  mutate(GENDER = as.factor(ifelse(grepl('MALE', pop_age_gender$DEMO),'MALE','FEMALE')),
         DEMO = gsub('_FEM','', DEMO),
         DEMO = gsub('_MALE','', DEMO),
         DEMO = case_when(DEMO == 'AGE004' ~ '0-04',
                          DEMO == 'AGE0509' ~ '05-09',
                          DEMO == 'AGE1014' ~ '10-14',
                          DEMO == 'AGE1519' ~ '15-19',
                          DEMO == 'AGE2024' ~ '20-24',
                          DEMO == 'AGE2529' ~ '25-29',
                          DEMO == 'AGE3034' ~ '30-34',
                          DEMO == 'AGE3539' ~ '35-39',
                          DEMO == 'AGE4044' ~ '40-44',
                          DEMO == 'AGE4549' ~ '45-49',
                          DEMO == 'AGE5054' ~ '50-54',
                          DEMO == 'AGE5559' ~ '55-59',
                          DEMO == 'AGE6064' ~ '60-64',
                          DEMO == 'AGE6569' ~ '65-69',
                          DEMO == 'AGE7074' ~ '70-74',
                          DEMO == 'AGE7579' ~ '75-79',
                          DEMO == 'AGE8084' ~ '80-84',
                          DEMO == 'AGE85PLUS' ~ '85 and Over'))

# Making ethnicity data frame
ethpop <- rbind(read_csv("cc-est2019-alldata-37.csv", show_col_types = F),
                   read_csv("cc-est2019-alldata-45.csv", show_col_types = F)) %>%
  mutate(CTYNAME = gsub(' County', '', CTYNAME),
         YEAR = as.integer(YEAR + 2007),
         WHITE = NHWA_MALE + NHWA_FEMALE,
         BLACK = NHBA_MALE + NHBA_FEMALE,
         HISPANIC = HWA_MALE + HWA_FEMALE + HBA_MALE + HBA_FEMALE + HIA_MALE + HIA_FEMALE + HAA_MALE + HAA_FEMALE + HNA_MALE + HNA_FEMALE + HIA_MALE + HIA_FEMALE,
         ASIAN = NHAA_MALE + NHAA_FEMALE,
         ISLANDER = NHNA_MALE + NHNA_FEMALE,
         NATIVE = NHIA_MALE + NHIA_FEMALE,
         MULTIRACIAL = TOM_MALE + TOM_FEMALE - HTOM_MALE - HTOM_FEMALE
         ) %>%
  filter(CTYNAME %in% counties, YEAR >= 3, AGEGRP == 0,
         !(STNAME == 'South Carolina' & CTYNAME == 'Union')) %>%
  select(STNAME, CTYNAME, YEAR, TOT_POP, WHITE, BLACK, HISPANIC, ASIAN, ISLANDER, NATIVE, MULTIRACIAL) %>%
  distinct()
ethpop <- ethpop %>%
  pivot_longer(cols = colnames(ethpop[,5:11]), names_to = 'ETHNICITY', values_to = 'POP')

# Making place of birth data frame
birthplace <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Indicator == 'Place of Birth',
         County %in% counties,
         !(Measure %in% foreign_detail)) %>%
  distinct()
birthplace <- birthplace %>% inner_join((birthplace %>% group_by(County, Year) %>% summarise(Total = sum(Numerator_value))), by = c('County', 'Year'))
`summarise()` has grouped output by 'County'. You can
override using the `.groups` argument.
# Making the unemployment data frame
unemployment <- rbind(read_excel('ur_anson.xlsx', trim_ws = T) %>% mutate(County = 'Anson', Period = gsub('M', '', Period)),
                      read_excel('ur_cabarrus.xlsx', trim_ws = T) %>% mutate(County = 'Cabarrus', Period = gsub('M', '', Period)),
                      read_excel('ur_catawba.xlsx', trim_ws = T) %>% mutate(County = 'Catawba', Period = gsub('M', '', Period)),
                      read_excel('ur_chester.xlsx', trim_ws=T, skip=11)[1:266,] %>% rename(Value = 'Observation Value') %>% mutate(County = 'Chester', Period = gsub('M','',Period)) %>% select(-Label),
                      read_excel('ur_cleveland.xlsx', trim_ws = T) %>% mutate(County = 'Cleveland', Period = gsub('M', '', Period)),
                      read_excel('ur_gaston.xlsx', trim_ws = T) %>% mutate(County = 'Gaston', Period = gsub('M', '', Period)),
                      read_excel('ur_iredell.xlsx', trim_ws = T) %>% mutate(County = 'Iredell', Period = gsub('M', '', Period)),
                      read_excel('ur_lancaster.xlsx', trim_ws = T) %>% mutate(County = 'Lancaster', Period = gsub('M', '', Period)),
                      read_excel('ur_lincoln.xlsx', trim_ws = T) %>% mutate(County = 'Lincoln', Period = gsub('M', '', Period)),
                      read_excel('ur_mecklenburg.xlsx', trim_ws = T) %>% mutate(County = 'Mecklenburg', Period = gsub('M', '', Period)),
                      read_excel('ur_rowan.xlsx', trim_ws = T) %>% mutate(County = 'Rowan', Period = gsub('M', '', Period)),
                      read_excel('ur_stanly.xlsx', trim_ws=T, skip=11)[1:266,] %>% rename(Value = 'Observation Value') %>% mutate(County = 'Stanly', Period = gsub('M','',Period)) %>% select(-Label),
                      read_excel('ur_union.xlsx', trim_ws = T) %>% mutate(County = 'Union', Period = gsub('M', '', Period)),
                      read_excel('ur_york.xlsx', trim_ws = T) %>% mutate(County = 'York', Period = gsub('M', '', Period))) %>%
  mutate(Year = as.integer(Year),
         Period = as.integer(Period),
         Date = as.Date(paste(Year,'-',Period, '-01', sep = '')),
         Value = Value/100) %>%
  rename(Month = Period,
         Unemployment = Value)

# Make income data frame
income <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Indicator == 'Income & Earnings',
         County %in% counties,
         Measure != 'Household Income: Total') %>%
  distinct()
income <- income %>% inner_join((income %>% group_by(County, Year) %>% summarise(Total = sum(Numerator_value))), by = c('County', 'Year'))
`summarise()` has grouped output by 'County'. You can
override using the `.groups` argument.
# Make education attainment data frame
education <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Indicator == 'Educational Attainment',
         County %in% counties,
         Measure %in% attainment_lvl) %>%
  distinct()
education <- education %>% inner_join((education %>% group_by(County, Year) %>% summarise(Total = sum(Numerator_value))), by = c('County', 'Year')) %>%
  mutate(
    Order = as.factor(case_when(
      Measure == 'Highest Degree: Less than a High School Diploma' ~ 1,
      Measure == 'Highest Degree: High School Diploma' ~ 2,
      Measure == 'Highest Degree: Some College, No Degree' ~ 3,
      Measure == "Highest Degree: Associate's Degree" ~ 4,
      Measure == "Highest Degree: Bachelor's Degree" ~ 5,
      Measure == "Highest Degree: Graduate or Professional Degree" ~ 6)),
    Measure = gsub("Highest Degree: ","",Measure))
`summarise()` has grouped output by 'County'. You can
override using the `.groups` argument.
# Make health care coverage data frame
coverage <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Indicator == 'Health Care Coverage',
         County %in% counties)
# Make housing age data frame
housing <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County),
         diff = Year-Numerator_value) %>%
  filter(Indicator == 'Housing Stock',
         County %in% counties)
# Make poverty figures data frame
poverty <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Measure == 'Individuals in Poverty',
         Theme == 'Social Well-Being',
         County %in% counties)
# Make transportation means data frame
transportation <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Theme == 'Transportation',
         Measure != 'Commuting Means Total',
         County %in% counties)

Demographics

Population

plot_ly(countypop %>% filter(YEAR == 2019), x = ~POPESTIMATE, y = ~CTYNAME, type = 'bar', color = ~CTYNAME, colors = color_a, orientation = 'h') %>%
  layout(title= '<b> Estimated County Population by Year </b>',
         xaxis= list(title='Population', tickformat=','),
         yaxis= list(title=''),
         legend= list(title=list(text='<b> Counties </b>')))

plot_ly(countypop, x=~YEAR, y=~CHANGE*100, color=~CTYNAME, type='scatter', mode='lines', colors=color_a) %>%
  layout(title= '<b> Change in County Population from Previous Year </b>',
         xaxis= list(title= 'Year'),
         yaxis= list(title= '% Change', ticksuffix='%', range=c(-2,4.5)),
         legend= list(title=list(text='<b> Counties </b>')))

Age & Gender

plot_ly(pop_age_gender %>% filter(YEAR == 2017, CTYNAME == 'Charlotte Region'),
        y=~DEMO, x=~PERCENTAGE*100,
        type='bar', color=~GENDER) %>%
  layout(title='<b> County Population Percentage by Age and Gender </b>',
         yaxis= list(title=''),
         xaxis= list(title='Population %', ticksuffix='%', range=c(0,5)),
         legend= list(title=list(text='<b> Gender </b>')))

Race & Ethnicity

plot_ly(ethpop %>% filter(YEAR == 2019),
        y=~CTYNAME, x=~(POP/TOT_POP)*100, color=~ETHNICITY,
        type='bar') %>%
  layout(barmode = 'stack',
         title='<b> County Population Percentage by Race </b>',
         legend=list(title=list(text='<b> Race </b>')),
         yaxis= list(title='County'),
         xaxis= list(title='Population %', ticksuffix='%', range=c(0,100)))

Place of Birth

plot_ly(birthplace %>% filter(Year == 2019),
        y=~County, x=~(Numerator_value/Total)*100, color=~Measure,
        type='bar') %>%
  layout(barmode = 'stack',
         title='<b> County Population Percentage by Place of Birth </b>',
         legend=list(title=list(text='<b> Place of Birth </b>')),
         yaxis= list(title='County'),
         xaxis= list(title='Population %', ticksuffix='%', range=c(0,100)))

Economy

Unemployment

plot_ly(unemployment, x=~Date, y=~Unemployment, color=~County, colors=color_a, type='scatter', mode='lines')

plot_ly(unemployment %>% filter(Year==2015, Month==6), x=~Unemployment, y=~County, color=~County, colors=color_a, type='bar')

6/21 Up to this point has been done in the shiny app

Income

#### DFs from Values.csv are missing Anson, Chester, and Stanly Counties
plot_ly(income %>% filter(Year == 2014), y=~County, x=~(Numerator_value/Total), color=~Measure, type='bar') %>%
  layout(barmode='stack')

Education

Educational Attainment

plot_ly(education %>% group_by(Year, Measure, County) %>%
  summarise(Numerator = sum(Numerator_value),
            Denominator = mean(Total)) %>% filter(Year == 2018, Measure == 'High School Diploma'), y=~County, color=~County, colors=color_na, x=~(Numerator/Denominator), type='bar')
`summarise()` has grouped output by 'Year', 'Measure'.
You can override using the `.groups` argument.

Health

Health Care Coverage

plot_ly(coverage %>%
         group_by(Year, County, Measure) %>%
         summarise(added=sum(Numerator_value)) %>%
         filter(Year==2016, !(Measure %in% c("Health Insurance Total"))),
       y=~County, x=~added, type='bar', color=~Measure)
`summarise()` has grouped output by 'Year', 'County'.
You can override using the `.groups` argument.
plot_ly(coverage %>%
         group_by(Year, County, Measure) %>%
         summarise(added=sum(Numerator_value)) %>%
         filter(Year==2016, Measure=='Children without Health Insurance'),
       y=~County, x=~added, type='bar', color=~County, colors=color_na)
`summarise()` has grouped output by 'Year', 'County'.
You can override using the `.groups` argument.
coverage %>% distinct(Measure)

Housing

Housing Age

housing %>% filter(Year == 2017) %>%
  ggplot(aes(x= County, y = Year-Numerator_value, fill = County)) +
  geom_col() +
  coord_flip()

# axis is giving double the true value
plot_ly(housing %>% filter(Year == 2014), y=~County, x=~diff,
        color=~County, colors=color_na, type='bar')

Social Well-Being

Poverty

plot_ly(poverty %>% filter(Year==2014),
        y=~County, x=~Numerator_value/Denominator_value,
        color=~County, colors=color_na, type='bar') %>%
      layout(xaxis=list(range=list(0,0.2)))

Transportation

##Commuting Modes

# Way too many missing values to create a substantive visualization.
transportation %>% filter(Year == 2014) %>%
  ggplot(aes(x = County, y = Numerator_value, fill = Measure, position = Measure)) +
  geom_col(position = 'dodge') +
  scale_y_continuous(labels = comma) +
  coord_flip()
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIExvYWQgUGFja2FnZXMNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCg0KIyBNYWtpbmcgRGF0YWZyYW1lcw0KYGBge3J9DQpjb2xvcl9hIDwtIGMoIiM1OGI1ZTEiLCIjMWM1YjVhIiwiIzQ2ZWJkYyIsIiMxZjQxOTYiLCIjZTI4ZGUyIiwiIzgxOGJkNyIsIiNlNGNjZjEiLCIjODIxODVmIiwiI2Y4NDliNiIsIiMwMDAwMDAiLCIjNWUzNGJjIiwiI2I3ZDE2NSIsIiMzMGQ1MmUiLCIjZmY1MzU3IikNCmNvbG9yX25hIDwtIGMoIiMxYzViNWEiLCIjNDZlYmRjIiwiI2UyOGRlMiIsIiM4MThiZDciLCIjZTRjY2YxIiwiIzgyMTg1ZiIsIiNmODQ5YjYiLCIjMDAwMDAwIiwiIzVlMzRiYyIsIiMzMGQ1MmUiLCIjZmY1MzU3IikNCmNvdW50aWVzIDwtIGMoJ0Fuc29uJywgJ0NhYmFycnVzJywgJ0NhdGF3YmEnLCAnQ2hlc3RlcicsICdDbGV2ZWxhbmQnLCAnR2FzdG9uJywgJ0lyZWRlbGwnLCAnTGFuY2FzdGVyJywgJ0xpbmNvbG4nLCAnTWVja2xlbmJ1cmcnLCAnUm93YW4nLCAnU3Rhbmx5JywgJ1VuaW9uJywgJ1lvcmsnKQ0KYXR0YWlubWVudF9sdmwgPC0gYygnSGlnaGVzdCBEZWdyZWU6IExlc3MgdGhhbiBhIEhpZ2ggU2Nob29sIERpcGxvbWEnLCAnSGlnaGVzdCBEZWdyZWU6IEhpZ2ggU2Nob29sIERpcGxvbWEnLCAnSGlnaGVzdCBEZWdyZWU6IFNvbWUgQ29sbGVnZSwgTm8gRGVncmVlJywgIkhpZ2hlc3QgRGVncmVlOiBBc3NvY2lhdGUncyBEZWdyZWUiLCAiSGlnaGVzdCBEZWdyZWU6IEJhY2hlbG9yJ3MgRGVncmVlIiwgIkhpZ2hlc3QgRGVncmVlOiBHcmFkdWF0ZSBvciBQcm9mZXNzaW9uYWwgRGVncmVlIikNCmZvcmVpZ25fZGV0YWlsIDwtIGMoJ0ZvcmVpZ24tQm9ybjogQWZyaWNhJywgJ0ZvcmVpZ24tQm9ybjogQXNpYScsICdGb3JlaWduLUJvcm46IEV1cm9wZScsICdGb3JlaWduLUJvcm46IExhdGluIEFtZXJpY2EnLCAnUGxhY2Ugb2YgQmlydGggVG90YWwnKQ0KDQpjb3VudHlwb3AgPC0gcmJpbmQocmVhZF9jc3YoImNjLWVzdDIwMTktYWdlc2V4LTM3LmNzdiIsIHNob3dfY29sX3R5cGVzID0gRiksDQogICAgICAgICAgICAgICAgICAgcmVhZF9jc3YoImNjLWVzdDIwMTktYWdlc2V4LTQ1LmNzdiIsIHNob3dfY29sX3R5cGVzID0gRikpICU+JQ0KICBzZWxlY3QoLVNVTUxFViwgLVNUQVRFLCAtQ09VTlRZKSAlPiUNCiAgbXV0YXRlKENUWU5BTUUgPSBnc3ViKCcgQ291bnR5JywgJycsIENUWU5BTUUpLA0KICAgICAgICAgWUVBUiA9IGFzLmludGVnZXIoWUVBUiArIDIwMDcpKSAlPiUNCiAgZmlsdGVyKENUWU5BTUUgJWluJSBjb3VudGllcywgWUVBUiA+PSAyMDEwLA0KICAgICAgICAgIShTVE5BTUUgPT0gJ1NvdXRoIENhcm9saW5hJyAmIENUWU5BTUUgPT0gJ1VuaW9uJykpICU+JQ0KICBkaXN0aW5jdCgpDQojIFllYXIgMyBpcyAyMDEwLCBZZWFyIDEyIGlzIDIwMTkNCg0KIyBNYWtpbmcgQ2hhcmxvdHRlIFJlZ2lvbg0KY3IgPC0gY291bnR5cG9wWzE6MTAsXSAlPiUNCiAgbXV0YXRlKENUWU5BTUUgPSAnQ2hhcmxvdHRlIFJlZ2lvbicpDQpmb3IoaSBpbiA0Omxlbmd0aChjb2xuYW1lcyhjb3VudHlwb3ApKSkgew0KICBmb3IoaiBpbiAxOjEwKXsNCiAgICBjcltqLGldIDwtIHN1bSgoY291bnR5cG9wICU+JSBmaWx0ZXIoWUVBUiA9PSBqKzIwMDkpKVtpXSkNCiAgfQ0KfQ0KDQojIE1ha2luZyBBZ2UgJiBHZW5kZXIgZGF0YSBmcmFtZQ0KcG9wX2FnZV9nZW5kZXIgPC0gcmJpbmQoY291bnR5cG9wLCBjcikNCmNvdW50eXBvcCA8LSBjciAlPiUgdHJhbnNtdXRlKFlFQVIgPSBZRUFSLCBDSEFSTE9UVEVQT1AgPSBQT1BFU1RJTUFURSkgJT4lIHJpZ2h0X2pvaW4oY291bnR5cG9wLCBieSA9ICdZRUFSJykgJT4lIG11dGF0ZShQUk9QT1JUSU9OID0gUE9QRVNUSU1BVEUgLyBDSEFSTE9UVEVQT1ApICU+JQ0KICBncm91cF9ieShDVFlOQU1FKSAlPiUNCiAgbXV0YXRlKENIQU5HRSA9IHJvdW5kKGlmZWxzZShZRUFSID09IDIwMTAsIDAsIFBPUEVTVElNQVRFL2xhZyhQT1BFU1RJTUFURSwgZGVmYXVsdCA9IGZpcnN0KFlFQVIpKSAtIDEpLDTimaYpKSAlPiUNCiAgdW5ncm91cCgpDQoNCnBvcF9hZ2VfZ2VuZGVyIDwtIHBvcF9hZ2VfZ2VuZGVyICU+JQ0KICBzZWxlY3QoLWNvbnRhaW5zKCdfVE9UJyksIC1QT1BFU1RfRkVNLCAtUE9QRVNUX01BTEUsIC1BR0UxNlBMVVNfTUFMRSwgLUFHRTE2UExVU19GRU0sIC1BR0UxOFBMVVNfRkVNLCAtQUdFMThQTFVTX01BTEUsIC1VTkRFUjVfRkVNLCAtVU5ERVI1X01BTEUsIC1BR0UxNTQ0X0ZFTSwgLUFHRTE1NDRfTUFMRSwgLU1FRElBTl9BR0VfRkVNLCAtTUVESUFOX0FHRV9NQUxFLCAtQUdFNjVQTFVTX0ZFTSwtQUdFNjVQTFVTX01BTEUsIC1BR0U1MTNfRkVNLCAtQUdFNTEzX01BTEUsIC1BR0U0NTY0X0ZFTSwgLUFHRTQ1NjRfTUFMRSwgLUFHRTI1NDRfRkVNLCAtQUdFMjU0NF9NQUxFLCAtQUdFMTgyNF9GRU0sIC1BR0UxODI0X01BTEUsIC1BR0UxNDE3X0ZFTSwgLUFHRTE0MTdfTUFMRSkgJT4lDQogIHJlbmFtZShBR0UwMDRfRkVNID0gQUdFMDRfRkVNLCBBR0UwMDRfTUFMRSA9IEFHRTA0X01BTEUsIEFHRTA1MDlfTUFMRSA9IEFHRTU5X01BTEUsIEFHRTA1MDlfRkVNID0gQUdFNTlfRkVNKQ0KcG9wX2FnZV9nZW5kZXIgPC0gcG9wX2FnZV9nZW5kZXIgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gY29sbmFtZXMocG9wX2FnZV9nZW5kZXJbLDU6NDBdKSwgbmFtZXNfdG8gPSAnREVNTycsIHZhbHVlc190byA9ICdQT1AnKSAlPiUNCiAgbXV0YXRlKFBFUkNFTlRBR0UgPSBQT1AvUE9QRVNUSU1BVEUpDQpwb3BfYWdlX2dlbmRlciA8LSBwb3BfYWdlX2dlbmRlciAlPiUNCiAgbXV0YXRlKEdFTkRFUiA9IGFzLmZhY3RvcihpZmVsc2UoZ3JlcGwoJ01BTEUnLCBwb3BfYWdlX2dlbmRlciRERU1PKSwnTUFMRScsJ0ZFTUFMRScpKSwNCiAgICAgICAgIERFTU8gPSBnc3ViKCdfRkVNJywnJywgREVNTyksDQogICAgICAgICBERU1PID0gZ3N1YignX01BTEUnLCcnLCBERU1PKSwNCiAgICAgICAgIERFTU8gPSBjYXNlX3doZW4oREVNTyA9PSAnQUdFMDA0JyB+ICcwLTA0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFMDUwOScgfiAnMDUtMDknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0UxMDE0JyB+ICcxMC0xNCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgIERFTU8gPT0gJ0FHRTE1MTknIH4gJzE1LTE5JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFMjAyNCcgfiAnMjAtMjQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0UyNTI5JyB+ICcyNS0yOScsDQogICAgICAgICAgICAgICAgICAgICAgICAgIERFTU8gPT0gJ0FHRTMwMzQnIH4gJzMwLTM0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFMzUzOScgfiAnMzUtMzknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0U0MDQ0JyB+ICc0MC00NCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgIERFTU8gPT0gJ0FHRTQ1NDknIH4gJzQ1LTQ5JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFNTA1NCcgfiAnNTAtNTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0U1NTU5JyB+ICc1NS01OScsDQogICAgICAgICAgICAgICAgICAgICAgICAgIERFTU8gPT0gJ0FHRTYwNjQnIH4gJzYwLTY0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFNjU2OScgfiAnNjUtNjknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0U3MDc0JyB+ICc3MC03NCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgIERFTU8gPT0gJ0FHRTc1NzknIH4gJzc1LTc5JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFODA4NCcgfiAnODAtODQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0U4NVBMVVMnIH4gJzg1IGFuZCBPdmVyJykpDQoNCiMgTWFraW5nIGV0aG5pY2l0eSBkYXRhIGZyYW1lDQpldGhwb3AgPC0gcmJpbmQocmVhZF9jc3YoImNjLWVzdDIwMTktYWxsZGF0YS0zNy5jc3YiLCBzaG93X2NvbF90eXBlcyA9IEYpLA0KICAgICAgICAgICAgICAgICAgIHJlYWRfY3N2KCJjYy1lc3QyMDE5LWFsbGRhdGEtNDUuY3N2Iiwgc2hvd19jb2xfdHlwZXMgPSBGKSkgJT4lDQogIG11dGF0ZShDVFlOQU1FID0gZ3N1YignIENvdW50eScsICcnLCBDVFlOQU1FKSwNCiAgICAgICAgIFlFQVIgPSBhcy5pbnRlZ2VyKFlFQVIgKyAyMDA3KSwNCiAgICAgICAgIFdISVRFID0gTkhXQV9NQUxFICsgTkhXQV9GRU1BTEUsDQogICAgICAgICBCTEFDSyA9IE5IQkFfTUFMRSArIE5IQkFfRkVNQUxFLA0KICAgICAgICAgSElTUEFOSUMgPSBIV0FfTUFMRSArIEhXQV9GRU1BTEUgKyBIQkFfTUFMRSArIEhCQV9GRU1BTEUgKyBISUFfTUFMRSArIEhJQV9GRU1BTEUgKyBIQUFfTUFMRSArIEhBQV9GRU1BTEUgKyBITkFfTUFMRSArIEhOQV9GRU1BTEUgKyBISUFfTUFMRSArIEhJQV9GRU1BTEUsDQogICAgICAgICBBU0lBTiA9IE5IQUFfTUFMRSArIE5IQUFfRkVNQUxFLA0KICAgICAgICAgSVNMQU5ERVIgPSBOSE5BX01BTEUgKyBOSE5BX0ZFTUFMRSwNCiAgICAgICAgIE5BVElWRSA9IE5ISUFfTUFMRSArIE5ISUFfRkVNQUxFLA0KICAgICAgICAgTVVMVElSQUNJQUwgPSBUT01fTUFMRSArIFRPTV9GRU1BTEUgLSBIVE9NX01BTEUgLSBIVE9NX0ZFTUFMRQ0KICAgICAgICAgKSAlPiUNCiAgZmlsdGVyKENUWU5BTUUgJWluJSBjb3VudGllcywgWUVBUiA+PSAzLCBBR0VHUlAgPT0gMCwNCiAgICAgICAgICEoU1ROQU1FID09ICdTb3V0aCBDYXJvbGluYScgJiBDVFlOQU1FID09ICdVbmlvbicpKSAlPiUNCiAgc2VsZWN0KFNUTkFNRSwgQ1RZTkFNRSwgWUVBUiwgVE9UX1BPUCwgV0hJVEUsIEJMQUNLLCBISVNQQU5JQywgQVNJQU4sIElTTEFOREVSLCBOQVRJVkUsIE1VTFRJUkFDSUFMKSAlPiUNCiAgZGlzdGluY3QoKQ0KZXRocG9wIDwtIGV0aHBvcCAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjb2xuYW1lcyhldGhwb3BbLDU6MTFdKSwgbmFtZXNfdG8gPSAnRVRITklDSVRZJywgdmFsdWVzX3RvID0gJ1BPUCcpDQoNCiMgTWFraW5nIHBsYWNlIG9mIGJpcnRoIGRhdGEgZnJhbWUNCmJpcnRocGxhY2UgPC0gcmVhZC5jc3YoJ1ZhbHVlcy5jc3YnKSAlPiUNCiAgbXV0YXRlKENvdW50eSA9IGdzdWIoJyBDb3VudHksIE5vcnRoIENhcm9saW5hJywgJycsIENvdW50eSksDQogICAgICAgICBDb3VudHkgPSBnc3ViKCcgQ291bnR5LCBTb3V0aCBDYXJvbGluYScsICcnLCBDb3VudHkpKSAlPiUNCiAgZmlsdGVyKEluZGljYXRvciA9PSAnUGxhY2Ugb2YgQmlydGgnLA0KICAgICAgICAgQ291bnR5ICVpbiUgY291bnRpZXMsDQogICAgICAgICAhKE1lYXN1cmUgJWluJSBmb3JlaWduX2RldGFpbCkpICU+JQ0KICBkaXN0aW5jdCgpDQpiaXJ0aHBsYWNlIDwtIGJpcnRocGxhY2UgJT4lIGlubmVyX2pvaW4oKGJpcnRocGxhY2UgJT4lIGdyb3VwX2J5KENvdW50eSwgWWVhcikgJT4lIHN1bW1hcmlzZShUb3RhbCA9IHN1bShOdW1lcmF0b3JfdmFsdWUpKSksIGJ5ID0gYygnQ291bnR5JywgJ1llYXInKSkNCg0KIyBNYWtpbmcgdGhlIHVuZW1wbG95bWVudCBkYXRhIGZyYW1lDQp1bmVtcGxveW1lbnQgPC0gcmJpbmQocmVhZF9leGNlbCgndXJfYW5zb24ueGxzeCcsIHRyaW1fd3MgPSBUKSAlPiUgbXV0YXRlKENvdW50eSA9ICdBbnNvbicsIFBlcmlvZCA9IGdzdWIoJ00nLCAnJywgUGVyaW9kKSksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfY2FiYXJydXMueGxzeCcsIHRyaW1fd3MgPSBUKSAlPiUgbXV0YXRlKENvdW50eSA9ICdDYWJhcnJ1cycsIFBlcmlvZCA9IGdzdWIoJ00nLCAnJywgUGVyaW9kKSksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfY2F0YXdiYS54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ0NhdGF3YmEnLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX2NoZXN0ZXIueGxzeCcsIHRyaW1fd3M9VCwgc2tpcD0xMSlbMToyNjYsXSAlPiUgcmVuYW1lKFZhbHVlID0gJ09ic2VydmF0aW9uIFZhbHVlJykgJT4lIG11dGF0ZShDb3VudHkgPSAnQ2hlc3RlcicsIFBlcmlvZCA9IGdzdWIoJ00nLCcnLFBlcmlvZCkpICU+JSBzZWxlY3QoLUxhYmVsKSwNCiAgICAgICAgICAgICAgICAgICAgICByZWFkX2V4Y2VsKCd1cl9jbGV2ZWxhbmQueGxzeCcsIHRyaW1fd3MgPSBUKSAlPiUgbXV0YXRlKENvdW50eSA9ICdDbGV2ZWxhbmQnLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX2dhc3Rvbi54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ0dhc3RvbicsIFBlcmlvZCA9IGdzdWIoJ00nLCAnJywgUGVyaW9kKSksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfaXJlZGVsbC54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ0lyZWRlbGwnLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX2xhbmNhc3Rlci54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ0xhbmNhc3RlcicsIFBlcmlvZCA9IGdzdWIoJ00nLCAnJywgUGVyaW9kKSksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfbGluY29sbi54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ0xpbmNvbG4nLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX21lY2tsZW5idXJnLnhsc3gnLCB0cmltX3dzID0gVCkgJT4lIG11dGF0ZShDb3VudHkgPSAnTWVja2xlbmJ1cmcnLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX3Jvd2FuLnhsc3gnLCB0cmltX3dzID0gVCkgJT4lIG11dGF0ZShDb3VudHkgPSAnUm93YW4nLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX3N0YW5seS54bHN4JywgdHJpbV93cz1ULCBza2lwPTExKVsxOjI2NixdICU+JSByZW5hbWUoVmFsdWUgPSAnT2JzZXJ2YXRpb24gVmFsdWUnKSAlPiUgbXV0YXRlKENvdW50eSA9ICdTdGFubHknLCBQZXJpb2QgPSBnc3ViKCdNJywnJyxQZXJpb2QpKSAlPiUgc2VsZWN0KC1MYWJlbCksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfdW5pb24ueGxzeCcsIHRyaW1fd3MgPSBUKSAlPiUgbXV0YXRlKENvdW50eSA9ICdVbmlvbicsIFBlcmlvZCA9IGdzdWIoJ00nLCAnJywgUGVyaW9kKSksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfeW9yay54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ1lvcmsnLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpKSAlPiUNCiAgbXV0YXRlKFllYXIgPSBhcy5pbnRlZ2VyKFllYXIpLA0KICAgICAgICAgUGVyaW9kID0gYXMuaW50ZWdlcihQZXJpb2QpLA0KICAgICAgICAgRGF0ZSA9IGFzLkRhdGUocGFzdGUoWWVhciwnLScsUGVyaW9kLCAnLTAxJywgc2VwID0gJycpKSwNCiAgICAgICAgIFZhbHVlID0gVmFsdWUvMTAwKSAlPiUNCiAgcmVuYW1lKE1vbnRoID0gUGVyaW9kLA0KICAgICAgICAgVW5lbXBsb3ltZW50ID0gVmFsdWUpDQoNCiMgTWFrZSBpbmNvbWUgZGF0YSBmcmFtZQ0KaW5jb21lIDwtIHJlYWQuY3N2KCdWYWx1ZXMuY3N2JykgJT4lDQogIG11dGF0ZShDb3VudHkgPSBnc3ViKCcgQ291bnR5LCBOb3J0aCBDYXJvbGluYScsICcnLCBDb3VudHkpLA0KICAgICAgICAgQ291bnR5ID0gZ3N1YignIENvdW50eSwgU291dGggQ2Fyb2xpbmEnLCAnJywgQ291bnR5KSkgJT4lDQogIGZpbHRlcihJbmRpY2F0b3IgPT0gJ0luY29tZSAmIEVhcm5pbmdzJywNCiAgICAgICAgIENvdW50eSAlaW4lIGNvdW50aWVzLA0KICAgICAgICAgTWVhc3VyZSAhPSAnSG91c2Vob2xkIEluY29tZTogVG90YWwnKSAlPiUNCiAgZGlzdGluY3QoKQ0KaW5jb21lIDwtIGluY29tZSAlPiUgaW5uZXJfam9pbigoaW5jb21lICU+JSBncm91cF9ieShDb3VudHksIFllYXIpICU+JSBzdW1tYXJpc2UoVG90YWwgPSBzdW0oTnVtZXJhdG9yX3ZhbHVlKSkpLCBieSA9IGMoJ0NvdW50eScsICdZZWFyJykpDQoNCiMgTWFrZSBlZHVjYXRpb24gYXR0YWlubWVudCBkYXRhIGZyYW1lDQplZHVjYXRpb24gPC0gcmVhZC5jc3YoJ1ZhbHVlcy5jc3YnKSAlPiUNCiAgbXV0YXRlKENvdW50eSA9IGdzdWIoJyBDb3VudHksIE5vcnRoIENhcm9saW5hJywgJycsIENvdW50eSksDQogICAgICAgICBDb3VudHkgPSBnc3ViKCcgQ291bnR5LCBTb3V0aCBDYXJvbGluYScsICcnLCBDb3VudHkpKSAlPiUNCiAgZmlsdGVyKEluZGljYXRvciA9PSAnRWR1Y2F0aW9uYWwgQXR0YWlubWVudCcsDQogICAgICAgICBDb3VudHkgJWluJSBjb3VudGllcywNCiAgICAgICAgIE1lYXN1cmUgJWluJSBhdHRhaW5tZW50X2x2bCkgJT4lDQogIGRpc3RpbmN0KCkNCmVkdWNhdGlvbiA8LSBlZHVjYXRpb24gJT4lIGlubmVyX2pvaW4oKGVkdWNhdGlvbiAlPiUgZ3JvdXBfYnkoQ291bnR5LCBZZWFyKSAlPiUgc3VtbWFyaXNlKFRvdGFsID0gc3VtKE51bWVyYXRvcl92YWx1ZSkpKSwgYnkgPSBjKCdDb3VudHknLCAnWWVhcicpKSAlPiUNCiAgbXV0YXRlKA0KICAgIE9yZGVyID0gYXMuZmFjdG9yKGNhc2Vfd2hlbigNCiAgICAgIE1lYXN1cmUgPT0gJ0hpZ2hlc3QgRGVncmVlOiBMZXNzIHRoYW4gYSBIaWdoIFNjaG9vbCBEaXBsb21hJyB+IDEsDQogICAgICBNZWFzdXJlID09ICdIaWdoZXN0IERlZ3JlZTogSGlnaCBTY2hvb2wgRGlwbG9tYScgfiAyLA0KICAgICAgTWVhc3VyZSA9PSAnSGlnaGVzdCBEZWdyZWU6IFNvbWUgQ29sbGVnZSwgTm8gRGVncmVlJyB+IDMsDQogICAgICBNZWFzdXJlID09ICJIaWdoZXN0IERlZ3JlZTogQXNzb2NpYXRlJ3MgRGVncmVlIiB+IDQsDQogICAgICBNZWFzdXJlID09ICJIaWdoZXN0IERlZ3JlZTogQmFjaGVsb3IncyBEZWdyZWUiIH4gNSwNCiAgICAgIE1lYXN1cmUgPT0gIkhpZ2hlc3QgRGVncmVlOiBHcmFkdWF0ZSBvciBQcm9mZXNzaW9uYWwgRGVncmVlIiB+IDYpKSwNCiAgICBNZWFzdXJlID0gZ3N1YigiSGlnaGVzdCBEZWdyZWU6ICIsIiIsTWVhc3VyZSkpDQojIE1ha2UgaGVhbHRoIGNhcmUgY292ZXJhZ2UgZGF0YSBmcmFtZQ0KY292ZXJhZ2UgPC0gcmVhZC5jc3YoJ1ZhbHVlcy5jc3YnKSAlPiUNCiAgbXV0YXRlKENvdW50eSA9IGdzdWIoJyBDb3VudHksIE5vcnRoIENhcm9saW5hJywgJycsIENvdW50eSksDQogICAgICAgICBDb3VudHkgPSBnc3ViKCcgQ291bnR5LCBTb3V0aCBDYXJvbGluYScsICcnLCBDb3VudHkpKSAlPiUNCiAgZmlsdGVyKEluZGljYXRvciA9PSAnSGVhbHRoIENhcmUgQ292ZXJhZ2UnLA0KICAgICAgICAgQ291bnR5ICVpbiUgY291bnRpZXMpDQojIE1ha2UgaG91c2luZyBhZ2UgZGF0YSBmcmFtZQ0KaG91c2luZyA8LSByZWFkLmNzdignVmFsdWVzLmNzdicpICU+JQ0KICBtdXRhdGUoQ291bnR5ID0gZ3N1YignIENvdW50eSwgTm9ydGggQ2Fyb2xpbmEnLCAnJywgQ291bnR5KSwNCiAgICAgICAgIENvdW50eSA9IGdzdWIoJyBDb3VudHksIFNvdXRoIENhcm9saW5hJywgJycsIENvdW50eSksDQogICAgICAgICBkaWZmID0gWWVhci1OdW1lcmF0b3JfdmFsdWUpICU+JQ0KICBmaWx0ZXIoSW5kaWNhdG9yID09ICdIb3VzaW5nIFN0b2NrJywNCiAgICAgICAgIENvdW50eSAlaW4lIGNvdW50aWVzKQ0KIyBNYWtlIHBvdmVydHkgZmlndXJlcyBkYXRhIGZyYW1lDQpwb3ZlcnR5IDwtIHJlYWQuY3N2KCdWYWx1ZXMuY3N2JykgJT4lDQogIG11dGF0ZShDb3VudHkgPSBnc3ViKCcgQ291bnR5LCBOb3J0aCBDYXJvbGluYScsICcnLCBDb3VudHkpLA0KICAgICAgICAgQ291bnR5ID0gZ3N1YignIENvdW50eSwgU291dGggQ2Fyb2xpbmEnLCAnJywgQ291bnR5KSkgJT4lDQogIGZpbHRlcihNZWFzdXJlID09ICdJbmRpdmlkdWFscyBpbiBQb3ZlcnR5JywNCiAgICAgICAgIFRoZW1lID09ICdTb2NpYWwgV2VsbC1CZWluZycsDQogICAgICAgICBDb3VudHkgJWluJSBjb3VudGllcykNCiMgTWFrZSB0cmFuc3BvcnRhdGlvbiBtZWFucyBkYXRhIGZyYW1lDQp0cmFuc3BvcnRhdGlvbiA8LSByZWFkLmNzdignVmFsdWVzLmNzdicpICU+JQ0KICBtdXRhdGUoQ291bnR5ID0gZ3N1YignIENvdW50eSwgTm9ydGggQ2Fyb2xpbmEnLCAnJywgQ291bnR5KSwNCiAgICAgICAgIENvdW50eSA9IGdzdWIoJyBDb3VudHksIFNvdXRoIENhcm9saW5hJywgJycsIENvdW50eSkpICU+JQ0KICBmaWx0ZXIoVGhlbWUgPT0gJ1RyYW5zcG9ydGF0aW9uJywNCiAgICAgICAgIE1lYXN1cmUgIT0gJ0NvbW11dGluZyBNZWFucyBUb3RhbCcsDQogICAgICAgICBDb3VudHkgJWluJSBjb3VudGllcykNCmBgYA0KDQoNCiMgRGVtb2dyYXBoaWNzDQojIyBQb3B1bGF0aW9uDQpgYGB7cn0NCnBsb3RfbHkoY291bnR5cG9wICU+JSBmaWx0ZXIoWUVBUiA9PSAyMDE5KSwgeCA9IH5QT1BFU1RJTUFURSwgeSA9IH5DVFlOQU1FLCB0eXBlID0gJ2JhcicsIGNvbG9yID0gfkNUWU5BTUUsIGNvbG9ycyA9IGNvbG9yX2EsIG9yaWVudGF0aW9uID0gJ2gnKSAlPiUNCiAgbGF5b3V0KHRpdGxlPSAnPGI+IEVzdGltYXRlZCBDb3VudHkgUG9wdWxhdGlvbiBieSBZZWFyIDwvYj4nLA0KICAgICAgICAgeGF4aXM9IGxpc3QodGl0bGU9J1BvcHVsYXRpb24nLCB0aWNrZm9ybWF0PScsJyksDQogICAgICAgICB5YXhpcz0gbGlzdCh0aXRsZT0nJyksDQogICAgICAgICBsZWdlbmQ9IGxpc3QodGl0bGU9bGlzdCh0ZXh0PSc8Yj4gQ291bnRpZXMgPC9iPicpKSkNCg0KcGxvdF9seShjb3VudHlwb3AsIHg9fllFQVIsIHk9fkNIQU5HRSoxMDAsIGNvbG9yPX5DVFlOQU1FLCB0eXBlPSdzY2F0dGVyJywgbW9kZT0nbGluZXMnLCBjb2xvcnM9Y29sb3JfYSkgJT4lDQogIGxheW91dCh0aXRsZT0gJzxiPiBDaGFuZ2UgaW4gQ291bnR5IFBvcHVsYXRpb24gZnJvbSBQcmV2aW91cyBZZWFyIDwvYj4nLA0KICAgICAgICAgeGF4aXM9IGxpc3QodGl0bGU9ICdZZWFyJyksDQogICAgICAgICB5YXhpcz0gbGlzdCh0aXRsZT0gJyUgQ2hhbmdlJywgdGlja3N1ZmZpeD0nJScsIHJhbmdlPWMoLTIsNC41KSksDQogICAgICAgICBsZWdlbmQ9IGxpc3QodGl0bGU9bGlzdCh0ZXh0PSc8Yj4gQ291bnRpZXMgPC9iPicpKSkNCmBgYA0KDQojIyBBZ2UgJiBHZW5kZXINCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoPSAxMCwgd2FybmluZz1GQUxTRX0NCnBsb3RfbHkocG9wX2FnZV9nZW5kZXIgJT4lIGZpbHRlcihZRUFSID09IDIwMTcsIENUWU5BTUUgPT0gJ0NoYXJsb3R0ZSBSZWdpb24nKSwNCiAgICAgICAgeT1+REVNTywgeD1+UEVSQ0VOVEFHRSoxMDAsDQogICAgICAgIHR5cGU9J2JhcicsIGNvbG9yPX5HRU5ERVIpICU+JQ0KICBsYXlvdXQodGl0bGU9JzxiPiBDb3VudHkgUG9wdWxhdGlvbiBQZXJjZW50YWdlIGJ5IEFnZSBhbmQgR2VuZGVyIDwvYj4nLA0KICAgICAgICAgeWF4aXM9IGxpc3QodGl0bGU9JycpLA0KICAgICAgICAgeGF4aXM9IGxpc3QodGl0bGU9J1BvcHVsYXRpb24gJScsIHRpY2tzdWZmaXg9JyUnLCByYW5nZT1jKDAsNSkpLA0KICAgICAgICAgbGVnZW5kPSBsaXN0KHRpdGxlPWxpc3QodGV4dD0nPGI+IEdlbmRlciA8L2I+JykpKQ0KYGBgDQoNCiMjIFJhY2UgJiBFdGhuaWNpdHkNCmBgYHtyfQ0KcGxvdF9seShldGhwb3AgJT4lIGZpbHRlcihZRUFSID09IDIwMTkpLA0KICAgICAgICB5PX5DVFlOQU1FLCB4PX4oUE9QL1RPVF9QT1ApKjEwMCwgY29sb3I9fkVUSE5JQ0lUWSwNCiAgICAgICAgdHlwZT0nYmFyJykgJT4lDQogIGxheW91dChiYXJtb2RlID0gJ3N0YWNrJywNCiAgICAgICAgIHRpdGxlPSc8Yj4gQ291bnR5IFBvcHVsYXRpb24gUGVyY2VudGFnZSBieSBSYWNlIDwvYj4nLA0KICAgICAgICAgbGVnZW5kPWxpc3QodGl0bGU9bGlzdCh0ZXh0PSc8Yj4gUmFjZSA8L2I+JykpLA0KICAgICAgICAgeWF4aXM9IGxpc3QodGl0bGU9J0NvdW50eScpLA0KICAgICAgICAgeGF4aXM9IGxpc3QodGl0bGU9J1BvcHVsYXRpb24gJScsIHRpY2tzdWZmaXg9JyUnLCByYW5nZT1jKDAsMTAwKSkpDQpgYGANCg0KIyMgUGxhY2Ugb2YgQmlydGgNCmBgYHtyfQ0KcGxvdF9seShiaXJ0aHBsYWNlICU+JSBmaWx0ZXIoWWVhciA9PSAyMDE5KSwNCiAgICAgICAgeT1+Q291bnR5LCB4PX4oTnVtZXJhdG9yX3ZhbHVlL1RvdGFsKSoxMDAsIGNvbG9yPX5NZWFzdXJlLA0KICAgICAgICB0eXBlPSdiYXInKSAlPiUNCiAgbGF5b3V0KGJhcm1vZGUgPSAnc3RhY2snLA0KICAgICAgICAgdGl0bGU9JzxiPiBDb3VudHkgUG9wdWxhdGlvbiBQZXJjZW50YWdlIGJ5IFBsYWNlIG9mIEJpcnRoIDwvYj4nLA0KICAgICAgICAgbGVnZW5kPWxpc3QodGl0bGU9bGlzdCh0ZXh0PSc8Yj4gUGxhY2Ugb2YgQmlydGggPC9iPicpKSwNCiAgICAgICAgIHlheGlzPSBsaXN0KHRpdGxlPSdDb3VudHknKSwNCiAgICAgICAgIHhheGlzPSBsaXN0KHRpdGxlPSdQb3B1bGF0aW9uICUnLCB0aWNrc3VmZml4PSclJywgcmFuZ2U9YygwLDEwMCkpKQ0KYGBgDQoNCg0KDQojIEVjb25vbXkNCiMjIFVuZW1wbG95bWVudA0KYGBge3J9DQpwbG90X2x5KHVuZW1wbG95bWVudCwgeD1+RGF0ZSwgeT1+VW5lbXBsb3ltZW50LCBjb2xvcj1+Q291bnR5LCBjb2xvcnM9Y29sb3JfYSwgdHlwZT0nc2NhdHRlcicsIG1vZGU9J2xpbmVzJykNCg0KcGxvdF9seSh1bmVtcGxveW1lbnQgJT4lIGZpbHRlcihZZWFyPT0yMDE1LCBNb250aD09NiksIHg9flVuZW1wbG95bWVudCwgeT1+Q291bnR5LCBjb2xvcj1+Q291bnR5LCBjb2xvcnM9Y29sb3JfYSwgdHlwZT0nYmFyJykNCmBgYA0KDQojIyMjIyMjIyMjIyMjIyMjICAgNi8yMSBVcCB0byB0aGlzIHBvaW50IGhhcyBiZWVuIGRvbmUgaW4gdGhlIHNoaW55IGFwcCAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQoNCiMjIEluY29tZQ0KYGBge3J9DQojIyMjIERGcyBmcm9tIFZhbHVlcy5jc3YgYXJlIG1pc3NpbmcgQW5zb24sIENoZXN0ZXIsIGFuZCBTdGFubHkgQ291bnRpZXMNCnBsb3RfbHkoaW5jb21lICU+JSBmaWx0ZXIoWWVhciA9PSAyMDE0KSwgeT1+Q291bnR5LCB4PX4oTnVtZXJhdG9yX3ZhbHVlL1RvdGFsKSwgY29sb3I9fk1lYXN1cmUsIHR5cGU9J2JhcicpICU+JQ0KICBsYXlvdXQoYmFybW9kZT0nc3RhY2snKQ0KYGBgDQoNCiMgRWR1Y2F0aW9uDQojIyBFZHVjYXRpb25hbCBBdHRhaW5tZW50DQpgYGB7cn0NCnBsb3RfbHkoZWR1Y2F0aW9uICU+JSBncm91cF9ieShZZWFyLCBNZWFzdXJlLCBDb3VudHkpICU+JQ0KICBzdW1tYXJpc2UoTnVtZXJhdG9yID0gc3VtKE51bWVyYXRvcl92YWx1ZSksDQogICAgICAgICAgICBEZW5vbWluYXRvciA9IG1lYW4oVG90YWwpKSAlPiUgZmlsdGVyKFllYXIgPT0gMjAxOCwgTWVhc3VyZSA9PSAnSGlnaCBTY2hvb2wgRGlwbG9tYScpLCB5PX5Db3VudHksIGNvbG9yPX5Db3VudHksIGNvbG9ycz1jb2xvcl9uYSwgeD1+KE51bWVyYXRvci9EZW5vbWluYXRvciksIHR5cGU9J2JhcicpDQpgYGANCg0KIyBIZWFsdGgNCiMjIEhlYWx0aCBDYXJlIENvdmVyYWdlDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnBsb3RfbHkoY292ZXJhZ2UgJT4lDQogICAgICAgICBncm91cF9ieShZZWFyLCBDb3VudHksIE1lYXN1cmUpICU+JQ0KICAgICAgICAgc3VtbWFyaXNlKGFkZGVkPXN1bShOdW1lcmF0b3JfdmFsdWUpKSAlPiUNCiAgICAgICAgIGZpbHRlcihZZWFyPT0yMDE2LCAhKE1lYXN1cmUgJWluJSBjKCJIZWFsdGggSW5zdXJhbmNlIFRvdGFsIikpKSwNCiAgICAgICB5PX5Db3VudHksIHg9fmFkZGVkLCB0eXBlPSdiYXInLCBjb2xvcj1+TWVhc3VyZSkNCg0KcGxvdF9seShjb3ZlcmFnZSAlPiUNCiAgICAgICAgIGdyb3VwX2J5KFllYXIsIENvdW50eSwgTWVhc3VyZSkgJT4lDQogICAgICAgICBzdW1tYXJpc2UoYWRkZWQ9c3VtKE51bWVyYXRvcl92YWx1ZSkpICU+JQ0KICAgICAgICAgZmlsdGVyKFllYXI9PTIwMTYsIE1lYXN1cmU9PSdDaGlsZHJlbiB3aXRob3V0IEhlYWx0aCBJbnN1cmFuY2UnKSwNCiAgICAgICB5PX5Db3VudHksIHg9fmFkZGVkLCB0eXBlPSdiYXInLCBjb2xvcj1+Q291bnR5LCBjb2xvcnM9Y29sb3JfbmEpDQpjb3ZlcmFnZSAlPiUgZGlzdGluY3QoTWVhc3VyZSkNCmBgYA0KIyBIb3VzaW5nDQojIyBIb3VzaW5nIEFnZQ0KYGBge3J9DQpob3VzaW5nICU+JSBmaWx0ZXIoWWVhciA9PSAyMDE3KSAlPiUNCiAgZ2dwbG90KGFlcyh4PSBDb3VudHksIHkgPSBZZWFyLU51bWVyYXRvcl92YWx1ZSwgZmlsbCA9IENvdW50eSkpICsNCiAgZ2VvbV9jb2woKSArDQogIGNvb3JkX2ZsaXAoKQ0KIyBheGlzIGlzIGdpdmluZyBkb3VibGUgdGhlIHRydWUgdmFsdWUNCnBsb3RfbHkoaG91c2luZyAlPiUgZmlsdGVyKFllYXIgPT0gMjAxNCksIHk9fkNvdW50eSwgeD1+ZGlmZiwNCiAgICAgICAgY29sb3I9fkNvdW50eSwgY29sb3JzPWNvbG9yX25hLCB0eXBlPSdiYXInKQ0KYGBgDQojIFNvY2lhbCBXZWxsLUJlaW5nDQojIyBQb3ZlcnR5DQpgYGB7cn0NCnBsb3RfbHkocG92ZXJ0eSAlPiUgZmlsdGVyKFllYXI9PTIwMTQpLA0KICAgICAgICB5PX5Db3VudHksIHg9fk51bWVyYXRvcl92YWx1ZS9EZW5vbWluYXRvcl92YWx1ZSwNCiAgICAgICAgY29sb3I9fkNvdW50eSwgY29sb3JzPWNvbG9yX25hLCB0eXBlPSdiYXInKSAlPiUNCiAgICAgIGxheW91dCh4YXhpcz1saXN0KHJhbmdlPWxpc3QoMCwwLjIpKSkNCmBgYA0KIyBUcmFuc3BvcnRhdGlvbg0KIyNDb21tdXRpbmcgTW9kZXMNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBXYXkgdG9vIG1hbnkgbWlzc2luZyB2YWx1ZXMgdG8gY3JlYXRlIGEgc3Vic3RhbnRpdmUgdmlzdWFsaXphdGlvbi4NCnRyYW5zcG9ydGF0aW9uICU+JSBmaWx0ZXIoWWVhciA9PSAyMDE0KSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gQ291bnR5LCB5ID0gTnVtZXJhdG9yX3ZhbHVlLCBmaWxsID0gTWVhc3VyZSwgcG9zaXRpb24gPSBNZWFzdXJlKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICdkb2RnZScpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArDQogIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCg0KDQoNCg==